
`include "defines.v"
/* verilator lint_off LATCH */
//----------------------------------------------------------------
//Module Name : cpu_ctrl_id.v
//Description of module:
//control signal genaration 
//----------------------------------------------------------------
//Designer:	Tang Pengyu
//Date: 2021/07/22	  
//----------------------------------------------------------------

module	cpu_ctrl_id(
//		input	clock,
		input	[7:0]	inst_opcode,
		input	branch_eq,
		input	branch_ne,
		input	branch_lt,
		input	branch_ge,
		input	branch_ltu,
		input	branch_geu,
//		input	[63:0] ram_addr,
		input	time_intr_r,			//中断响应
//		input	[63:0] load_store_addr,			//exe_data
		
		input	[6:0]	funct7,
		
//		input	if_fetched,	

		output	jalr_en,
		output	jal_en,		
		output	[1:0] wb_sel,
		output	reg pc_sel,
		output	branch_en,
		output	ecall_en,
		output	mret_en,
		
		input	[63:0]	op1,
		input	[63:0]	op2,
		input	[63:0]	extend_imm,
		input	if_fetched,
		input	[63:0]	pc_out,
		output	[63:0]	jump_addr,
		output	load_mem_en,
		
		output	load_axi_en,
		output	load_clint_en,
		output	store_axi_en,
		output	store_clint_en,
		output	store_mem_en

);
assign jalr_en = (inst_opcode == 8'b000_11001);
assign jal_en = (inst_opcode[4:0] == 5'b11011);
wire	jal_jalr_en;
assign jal_jalr_en = jal_en | jalr_en;
//wire	load_mem_en;
assign load_mem_en = (inst_opcode == 8'b000_00000) | (inst_opcode == 8'b100_00000)
					| (inst_opcode == 8'b001_00000) | (inst_opcode == 8'b101_00000)
					| (inst_opcode == 8'b010_00000) | (inst_opcode == 8'b110_00000)
					| (inst_opcode == 8'b011_00000);
assign wb_sel = {load_mem_en,jal_jalr_en};

wire	[63:0]	adder;
assign	adder = op1 + op2;
assign store_mem_en = (inst_opcode == 8'b000_01000) | (inst_opcode == 8'b001_01000)
					| (inst_opcode == 8'b010_01000) | (inst_opcode == 8'b011_01000);			//sb,sh,sw,sd	

//always @(*)	begin
//	if(if_fetched == 1'b1)	begin
assign		load_clint_en = load_mem_en & 
			((adder == 64'h0000_0000_0200_bff8) | (adder == 64'h0000_0000_0200_4000));
assign		store_clint_en = store_mem_en &
			(((op1 + extend_imm) == 64'h0000_0000_0200_bff8) | ((op1 + extend_imm) == 64'h0000_0000_0200_4000));

//	end
//end	
assign	load_axi_en = load_mem_en & (~load_clint_en);
assign	store_axi_en = store_mem_en & (~store_clint_en);				
//pc_sel_t
reg		pc_sel_t;
always @(*)
  begin
	case(inst_opcode)
		8'b000_11001:	pc_sel_t = 1'b1;			//inst_jalr
		8'b000_11011,8'b001_11011,8'b010_11011,8'b011_11011,8'b100_11011,8'b101_11011,8'b110_11011,8'b111_11011:	
						pc_sel_t = 1'b1;			//inst_jal
		8'b000_11000:	pc_sel_t = branch_eq ? 1'b1 : 1'b0;			//beq
		8'b001_11000:	pc_sel_t = branch_ne ? 1'b1 : 1'b0;			//bne
		8'b100_11000:	pc_sel_t = branch_lt ? 1'b1 : 1'b0;			//blt
		8'b101_11000:	pc_sel_t = branch_ge ? 1'b1 : 1'b0;			//bge
		8'b110_11000:	pc_sel_t = branch_ltu ? 1'b1 : 1'b0;			//bltu
		8'b111_11000:	pc_sel_t = branch_geu ? 1'b1 : 1'b0;			//bgeu
		
		8'b000_11100:	pc_sel_t = 1'b1;					//ecall
		default:		pc_sel_t = 1'b0;
  
	endcase
  end
//wire	pc_sel_p;  
assign	pc_sel= time_intr_r ? 1'b1 : pc_sel_t;		//产生中断时一定跳转

assign	jump_addr = jalr_en ? adder :
					(pc_out + extend_imm);
					//beq bne blt bge bltu bgeu
assign	branch_en = (inst_opcode == 8'b000_11000) | (inst_opcode == 8'b001_11000)
					| (inst_opcode == 8'b100_11000) | (inst_opcode == 8'b101_11000)
					| (inst_opcode == 8'b110_11000) | (inst_opcode == 8'b111_11000);
					
//ecall_en
assign	ecall_en = (inst_opcode == 8'b000_11100) ? 
					((funct7 == 7'b0000000) ? 1'b1 : 1'b0) : 1'b0;
					
//mret_en
assign	mret_en = (inst_opcode == 8'b000_11100) ?
					((funct7 == 7'b0011000) ? 1'b1 : 1'b0) : 1'b0;

endmodule